/******************************************************************************
Project    : Real time rtsp server library base on live555
*******************************************************************************
File Name    :  <Mp2TsRTimeFramedSource.cpp>:  mp2ts real time framed source source file
Module Name  :  
Description  :  None
History      :
 No.   Ver.     Date        Designed by  Comment
-----+--------+----------+------------+---------------------------------------
 001   0.00.01  05/29/2015  <3G@LIURENHUA>   <mp2ts real time framed source source file>
*******************************************************************************/
#include "Mp2TsRTimeFramedSource.h"

/******************************************************************************
  static class member define
 ******************************************************************************/
int Mp2TsRTimeFramedSource::fHandID = 110;

/******************************************************************************
  class functions define
 ******************************************************************************/
Mp2TsRTimeFramedSource* Mp2TsRTimeFramedSource::createNew(
								UsageEnvironment & env,
#ifdef LOCAL_SOCK_INPUT
								const char  *pcIdentity,
								const u_int32_t unSBufSize,
								const u_int32_t unRBufSize,
#else
								queue_t *pstQue,
#endif /* LOCAL_SOCK_INPUT */
								unsigned preferredFrameSize)
{
	return new Mp2TsRTimeFramedSource(env,
#ifdef LOCAL_SOCK_INPUT
								pcIdentity,
								unSBufSize,
								unRBufSize,
#else
								pstQue,
#endif /* LOCAL_SOCK_INPUT */
								preferredFrameSize);
}

Mp2TsRTimeFramedSource::Mp2TsRTimeFramedSource(
								UsageEnvironment & env,
#ifdef LOCAL_SOCK_INPUT
							       const char  *pcIdentity,
								const u_int32_t unSBufSize,
								const u_int32_t unRBufSize,
#else
								queue_t *pstQue,
#endif /* LOCAL_SOCK_INPUT */
								unsigned preferredFrameSize) 
								: FramedSource(env)
{
#ifdef FRAME_DEBUG
	printf("-------------enter [%s]-------------\n", __func__);
#endif /* FRAME_DEBUG */

	/* Clear class members */
	fPreferredFrameSize = preferredFrameSize;
	fHaveStartedReading = False;
#ifdef LOCAL_SOCK_INPUT
	pstServer = NULL;

	/* Initialize local udp socket with identity */
	if( (LSOCK_ERR_NOERR != 
		eInitLocalUdpSocket(&pstServer, pcIdentity, 
		LSOCK_TYPE_S, unSBufSize, unRBufSize)) ){
		printf("[%s]initialize local udp socket failed\n",
			__func__);
		return;
	}
#else
	fObjHandID = fHandID++;
	m_que = pstQue;
#endif /* LOCAL_SOCK_INPUT */
}

Mp2TsRTimeFramedSource::~Mp2TsRTimeFramedSource()
{
#ifdef FRAME_DEBUG
	printf("-------------enter [%s]-------------\n", __func__);
#endif /* FRAME_DEBUG */

#ifndef READ_FROM_FILES_SYNCHRONOUSLY
	envir().taskScheduler().turnOffBackgroundReadHandling(
#ifdef LOCAL_SOCK_INPUT
		pstServer->sock
#else
		fObjHandID
#endif /* LOCAL_SOCK_INPUT */
		);
#endif /* READ_FROM_FILES_SYNCHRONOUSLY */

#ifdef LOCAL_SOCK_INPUT
	if( (NULL != pstServer) ){
		vDInitLocalUdpSocket(pstServer);
		pstServer = NULL;
	}
#endif /* LOCAL_SOCK_INPUT */
}

void Mp2TsRTimeFramedSource::doGetNextFrame()
{
#ifdef FRAME_DEBUG
	printf("-----enter [%s][%d]-----\n", 
		__func__, fMaxSize);
#endif /* FRAME_DEBUG */

#ifdef READ_FROM_FILES_SYNCHRONOUSLY
	doRealTimeRead();
#else
	  if ( (!fHaveStartedReading) ) {
		envir().taskScheduler().turnOnBackgroundReadHandling(
#ifdef LOCAL_SOCK_INPUT
			pstServer->sock,
#else
			fObjHandID,
#endif /* LOCAL_SOCK_INPUT */
		   	(TaskScheduler::BackgroundHandlerProc*)
		   	&RTimeReadableHandler, this);
		fHaveStartedReading = True;
	  }
#endif /* READ_FROM_FILES_SYNCHRONOUSLY */
}

void Mp2TsRTimeFramedSource::doStopGettingFrames() 
{
	envir().taskScheduler().unscheduleDelayedTask(nextTask());
#ifndef READ_FROM_FILES_SYNCHRONOUSLY
	envir().taskScheduler().turnOffBackgroundReadHandling(
#ifdef LOCAL_SOCK_INPUT
		pstServer->sock
#else
		fObjHandID
#endif /* LOCAL_SOCK_INPUT */
		);
	fHaveStartedReading = False;
#endif /* READ_FROM_FILES_SYNCHRONOUSLY */
}

void Mp2TsRTimeFramedSource::RTimeReadableHandler(
	Mp2TsRTimeFramedSource* source, int /*mask*/) 
{
	if ( (!source->isCurrentlyAwaitingData()) ) {
		source->doStopGettingFrames();
		return;
	}
	source->doRealTimeRead();
}

void Mp2TsRTimeFramedSource::doRealTimeRead() 
{
	int read = 0;
	fFrameSize = 0;

	/* Checking frame size */
	if (fPreferredFrameSize > 0 
		&& fPreferredFrameSize < fMaxSize) {
		fMaxSize = fPreferredFrameSize;
	}
	
	/* Initialize require read size */
	read = fMaxSize;
#ifdef LOCAL_SOCK_INPUT // disable LOCAL_SOCK_INPUT in ../Android.mk
	/* Receive encode data from encoder */
	if( (LSOCK_ERR_NOERR == 
		eRecvDataByLUdpSock(pstServer, fTo, &read)) ){
		if( (read <= 0) ){
			printf("[%s]no data = %d\n", __func__, read);
			fNumTruncatedBytes = 0;
			return;
		}
	}else{
		printf("[%s]receive data failed from local socket\n", 
			__func__);
		fNumTruncatedBytes = 0;
		return;
	}
#else
	AVPacket *pkt =  (AVPacket *)q_pop_tail(m_que);
	if( (NULL != pkt) ){
		if( (pkt->size <= read) ){
			fNumTruncatedBytes = 0;
			read = pkt->size;
		}else{
			fNumTruncatedBytes = pkt->size - read;
		}
		if( (NULL != pkt->data) ){
			memcpy(fTo, pkt->data, read);
			free(pkt->data);
		}
		free(pkt);
	}else{
		fNumTruncatedBytes = 0;
		return;
	}
#endif /* LOCAL_SOCK_INPUT */

#ifdef LOCAL_SOCK_INPUT
	fNumTruncatedBytes = 0;
#endif /* LOCAL_SOCK_INPUT */
	fFrameSize = read;
	if ( (fFrameSize == 0) ) {
		handleClosure();
    		return;
  	}
	/* Set the 'presentation time' */
	gettimeofday(&fPresentationTime, NULL);

#ifdef READ_FROM_FILES_SYNCHRONOUSLY
	/* To avoid possible infinite 
	    recursion, we need to return to the event loop to do this */
  	nextTask() = envir().taskScheduler().scheduleDelayedTask(
		0, (TaskFunc*)FramedSource::afterGetting, this);
#else
	FramedSource::afterGetting(this);
#endif /* READ_FROM_FILES_SYNCHRONOUSLY */
}
